#include "stdafx.h"
#include "Device.h"
#include "Engine.h"
#include "SetupInfo.h"

Graphics::Device::Device()
{
	
}

Graphics::Device::~Device()
{

}

bool Graphics::Device::InitDevice(HINSTANCE aHInstance, const SetupInfo& aSetupInfo)
{
	myHInstance = aHInstance;

	

	DL_PRINT("Creating game window...");
	DL_CHK_CRITICAL(SetupWindow(aSetupInfo), "Error creating window!");

	DL_PRINT("Initializing D3D and D3DDevice...");
	DL_CHK_CRITICAL(InitD3DDevice(aSetupInfo), "Error initializing D3D");

	ShowWindow( myWindow, SW_SHOWDEFAULT );
	UpdateWindow( myWindow );

	return true;
}

void Graphics::Device::Destroy()
{
	if(myDevice != NULL)
		myDevice->Release();
	if(myD3D != NULL)
		myD3D->Release();
}

LPDIRECT3DDEVICE9 Graphics::Device::GetDevice()
{
	return myDevice;
}

HWND Graphics::Device::GetWindow()
{
	return myWindow;
}

bool Graphics::Device::SetupWindow(const SetupInfo& aSetupInfo)
{

	DL_CHK_ASSERT(aSetupInfo.windowProc != NULL, "No WindowProc assigned to setup info");

	// Register the window class.
	WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, aSetupInfo.windowProc, 0L, 0L, 
		GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
		"The Attic", NULL };

	RegisterClassEx( &wc );

	// Create the application's window.

	if(aSetupInfo.windowed)
	{
		myWindow = CreateWindow("The Attic", aSetupInfo.title.c_str(),
			WS_OVERLAPPEDWINDOW, static_cast<int>(aSetupInfo.position.x), static_cast<int>(aSetupInfo.position.y), static_cast<int>(aSetupInfo.resolution.x), static_cast<int>(aSetupInfo.resolution.y),
			GetDesktopWindow(), NULL, wc.hInstance, NULL );

		DL_CHK_ASSERT(myWindow != NULL, "CreateWindow return NULL");

		if(aSetupInfo.borders == false)
		{
			LONG lStyle = GetWindowLong(myWindow, GWL_STYLE);
			lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
			SetWindowLong(myWindow, GWL_STYLE, lStyle);

			RECT rcWindow;
			GetWindowRect(myWindow, &rcWindow);
			// First move to force a repaint (?)
			MoveWindow(myWindow,0, 0, (rcWindow.right - rcWindow.left) - 1, (rcWindow.bottom - rcWindow.top) - 1, TRUE);
			MoveWindow(myWindow,rcWindow.left, rcWindow.top, (rcWindow.right - rcWindow.left), (rcWindow.bottom - rcWindow.top), TRUE);
		}
		else
		{
			RECT rcClient, rcWindow;
			POINT ptDiff;
			GetClientRect(myWindow, &rcClient);
			GetWindowRect(myWindow, &rcWindow);
			ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
			ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
			MoveWindow(myWindow,rcWindow.left, rcWindow.top, static_cast<int>(aSetupInfo.resolution.x) + ptDiff.x, static_cast<int>(aSetupInfo.resolution.y) + ptDiff.y, TRUE);
		}
	}
	else
	{
		myWindow = CreateWindow("The Attic", aSetupInfo.title.c_str(), 
			WS_EX_TOPMOST | WS_POPUP, 0, 0, static_cast<int>(aSetupInfo.resolution.x), static_cast<int>(aSetupInfo.resolution.y),
			GetDesktopWindow(), NULL, wc.hInstance, NULL );

		DL_CHK_ASSERT(myWindow != NULL, "CreateWindow return NULL");
	}

	RECT rcWindow, rcClient;
	GetWindowRect(myWindow, &rcWindow);
	GetClientRect(myWindow, &rcClient);
	DL_PRINT("Game window created successfully");
	DL_Debug::GetDebugInstance()->IncreaseTabCount();
	DL_PRINT(ExtendedString("Window size: ") << rcWindow.right - rcWindow.left << "x" << rcWindow.bottom - rcWindow.top);
 	DL_PRINT(ExtendedString("Window position: ") << "x:" << rcWindow.left << " y:" << rcWindow.top);
 	DL_PRINT(ExtendedString("Client area size: ") << rcClient.right - rcClient.left << "x" << rcClient.bottom - rcClient.top);
 	DL_PRINT(ExtendedString("Client area position: ") << "x:" << rcClient.left << " y:" << rcClient.top);
	DL_PRINT(ExtendedString("Windowed: ") << (aSetupInfo.windowed == true ? "true" : "false"));
	DL_Debug::GetDebugInstance()->DecreaseTabCount();

	return true;
}

bool Graphics::Device::InitD3DDevice(const SetupInfo& aSetupInfo)
{
	// Create the D3D object, which is needed to create the D3DDevice.
	if( NULL == ( myD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
	{
		return false;
	}

	DL_PRINT("D3D created sucessfully");

	// Set up the structure used to create the D3DDevice. Most parameters are
	// zeroed out. We set Windowed to TRUE, since we want to do D3D in a
	// window, and then set the SwapEffect to "discard", which is the most
	// efficient method of presenting the back buffer to the display.  And 
	// we request a back buffer format that matches the current desktop display 
	// format.
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory( &d3dpp, sizeof( d3dpp ) );
	d3dpp.Windowed = aSetupInfo.windowed;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dpp.BackBufferWidth = static_cast<UINT>(aSetupInfo.resolution.x);
	d3dpp.BackBufferHeight = static_cast<UINT>(aSetupInfo.resolution.y);

	// Create the Direct3D device. Here we are using the default adapter (most
	// systems only have one, unless they have multiple graphics hardware cards
	// installed) and requesting the HAL (which is saying we want the hardware
	// device rather than a software one). Software vertex processing is 
	// specified since we know it will work on all cards. On cards that support 
	// hardware vertex processing, though, we would see a big performance gain 
	// by specifying hardware vertex processing.
	HRESULT hr = myD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, myWindow,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp, &myDevice);
	if(FAILED(hr))
	{
		return false;
	}

	DL_PRINT("D3DDevice created sucessfully");

	D3DADAPTER_IDENTIFIER9 identifier;
	hr = myD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier);

	DL_INCREASETAB;
	DL_PRINT(ExtendedString("Display adapter: ") << identifier.Description);
	DL_PRINT(ExtendedString("Driver info"));
	DL_INCREASETAB;
	DL_PRINT(ExtendedString("Product: ") << HIWORD(identifier.DriverVersion.HighPart));
	DL_PRINT(ExtendedString("Version: ") << LOWORD(identifier.DriverVersion.HighPart));
	DL_PRINT(ExtendedString("Sub-version: ") << HIWORD(identifier.DriverVersion.LowPart));
	DL_PRINT(ExtendedString("Build: ") << LOWORD(identifier.DriverVersion.LowPart));
	DL_DECREASETAB;
	DL_DECREASETAB;

	// Device state would normally be set here

	myDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, 1);

	return true;
}


